home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 52
/
Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso
/
Aminet
/
misc
/
emu
/
Apex-src.lha
/
BUG.68K
< prev
next >
Wrap
Text File
|
2001-09-30
|
44KB
|
1,504 lines
;BUG.68K APR-21-88
;A debugger similar to Stride's SDT.
; by Loren Blaney
;
;REVISION HISTORY:
;FEB-22-87, Original based on version by King & Knight, transcribed by
; John Klein
;APR-21-88, Modified for Mac II. Uses Apex system console.
;
;COMMANDS:
;
; DISPLAY:
; Dm addr Display memory
; DR Display registers
; DDn Display Data registers (n is ignored)
; DAn Display Address registers
; DPc Display Program Counter register
; DUsp Display User Stack Pointer register (SSP = A7)
; DSr Display Status register (not SSP)
; DBn Display breakpoints
;
; SET:
; Sm addr Set memory
; SR val Set register (begins with D0)
; SDn val Set Data register
; SAn val Set Address register
; SPc val Set Program Counter register
; SUsp val Set User Stack Pointer register
; SSr val Set Status register
; SBn val Set breakpoint (0= cleared)
;
; SET MODE COMMANDS:
; 00000400: 2345 = val
; 00000402: 0AF0 =
; Return and down arrow move to next word
; Up arrow moves back a word
; Multiple entries may be made on one line
; Period (.) (RETURN) terminates entry mode
; Registers are set the same way
;
;
; EXECUTE:
; Go pc Go execute at address (PC). Defaults to current PC
; if address is not specified. That is, it resumes after
; a breakpoint. Notice that if you Go directly to a
; location which contains a breakpoint, it will not break.
; Tr pc Trace beginning at address (PC). Defaults work same as
; Go command. Breakpoints have no effect.
;
;
; MISCELLENA
; F s e p Fill (byte, word, or long is determined by pattern size)
; M s e t Move memory start.end>to
;* C s e t Compare memory start.end>to
;* L s e p Look for pattern (mask byte??)
;* H Help (also help key)
;* R u b a s Read and write disk blocks (unit, block, addr, size)
;* W u b a s
;
; Z bytes Set frame size for memory dump
;* Download
; CTRL-C Jump back to main command mode
; CTRL-P Restart and reinitialize the debugger
;
;* Indicates unimplemented features.
;
;======================================================================
NOLIST
INCLUDE SYSPAG
LIST
;ADDITIONAL ASCII CHARACTERS:
UP EQU 'K'-CTRL ;Up arrow
DOWN EQU 'J'-CTRL ;Down arrow
SSPDEF EQU $3000 ;Default supervisor stack pointer
SRDEF EQU $2000 ;Supervisor mode
SIZEDEF EQU $40 ;Default memory display frame size
;----------------------------------------------------------------------
ORG $400
JMP START.L
RAMBASE ORG $1000
;The following tables must be in order because of the way SETREG works
SAVD DS.L 8 ;Space for 8 data registers
SAVA DS.L 8 ;Space for 8 address registers
SAVPC DS.L 1 ;Space for program counter
SAVUSP DS.L 1 ;Space for user stack pointer
SAVSR DS.L 1 ;Space for status register
DS.L 1 ;Dummy spacer
BRKITBL DS.W 8 ;Space for 8 breakpoint instructions
BRKATBL DS.L 8 ;Space for 8 breakpoint addresses
; (only the low word is actually used)
; (end order restriction)
ACCESS DS.L 1 ;Bus and address error access address
FUNCODE DS.W 1 ;Bus and address error function code
ADDRDIS DS.L 1 ;Default address for memory display
ADDRSET DS.L 1 ;Default address for memory set
SIZEDIS DS.L 1 ;Memory display frame size (bytes)
BPFLAG DS.B 1 ;Flag: resume execution thru breakpoint
GOFLAG DS.B 1 ;Flag: user's program is running
BKCHAR DS.B 1 ;Last char read by CHIN
BKFLAG DS.B 1 ;Flag: BACKUP command, reread last char
RAMEND EQU @ ;End of RAM area (+1)
;======================================================================
;DEBUGGER ENTRY POINT
;
BASE EQU $3000
ORG BASE
; ORG $7EF00
START BSR INIT
RESTART BSR CRLF ;(Entry from CTRL-C)
GETCMD BSR TEXT ;Display prompt message
ASCII 'BUG'
DC.B '>' + $80
BSR OPENI ;Flush keyboard buffer
BSR GETCH ;Get uppercase character into D0
LEA CMDTBL.L,A0 ;Point to command search table
BSR EXECUTE ;Call routine to handle command
BRA.S GETCMD ;Loop back
;Main command table:
CMDTBL DC.W 'D' ;Display memory and registers
DC.W CMD_D_-CMDTBL
DC.W CR ;Display memory
DC.W CMD_DM-CMDTBL
DC.W DOWN ;Display memory
DC.W CMD_DM-CMDTBL
DC.W UP ;Display memory
DC.W CMD_DMU-CMDTBL
DC.W 'S' ;Set memory and registers
DC.W CMD_S_-CMDTBL
DC.W 'G' ;Start or continue program (Go)
DC.W CMD_G-CMDTBL
DC.W 'T' ;Trace program
DC.W CMD_T-CMDTBL
DC.W 'F' ;Fill memory with pattern
DC.W CMD_F-CMDTBL
DC.W 'M' ;Move a block of memory
DC.W CMD_M-CMDTBL
DC.W 'Z' ;Move a block of memory
DC.W CMD_Z-CMDTBL
DC.W $00 ;Mark end of table
DC.W CMD_BAD-CMDTBL ;Routine to handle illegal commands
;----------------------------------------------------------------------
;Routine to handle illegal commands
;
CMD_BAD BSR TEXT
ASCII 'I BEG YOUR PARDON?'
DC.B BEL, CR + $80
RTS
;----------------------------------------------------------------------
;Initialization stuff (mostly cold start)
;
INIT BSR OPEN
;Set up the exception vectors.
;First, set all vectors to the unassigned exception handler.
;This fills memory locations $0000 - $00FF.
LEA UA_EXCP.L,A1 ;Address of unassigned exception handler
SUBA.L A0,A0 ;Point to location 0
MOVE.W #63,D0 ;Get number of vectors (-1)
INIT10 MOVE.L A1,(A0)+
DBF D0,INIT10
LEA IN_EXCP.L,A1 ;Address of unassigned interrupt handler
MOVE.W #191,D0 ;Get number of vectors (-1)
INIT15 MOVE.L A1,(A0)+ ;Resume loading where unassigned vectors
DBF D0,INIT15 ; left off
LEA $64,A0 ;Point to start of interrupt autovectors
MOVE.W #7,D0 ;Get number of vectors (-1)
INIT17 MOVE.L A1,(A0)+
DBF D0,INIT17
LEA TI_EXCP.L,A1
LEA $80,A0 ;Set up TRAP vectors
MOVE.W #15,D0 ;Get number of exception vectors (-1)
INIT19 MOVE.L A1,(A0)+
DBF D0,INIT19
;Now, set up the other vectors.
LEA VECTBL.L,A1 ;Point to table of vectors
SUBA.L A0,A0 ;Point to location 0
MOVE.W #11,D0 ;Get number of exception vectors -1
INIT20 MOVE.L (A1)+,(A0)+
DBF D0,INIT20
LEA $60,A0 ;Set up spurious interrupt vector
MOVE.L (A1)+,(A0)
LEA $BC,A0 ;Set up breakpoint TRAP (15)
MOVE.L (A1)+,(A0)
LEA RAMBASE.L,A0 ;Clear all variables
MOVE.W #[RAMEND-RAMBASE]/4-1,D0 ;Size of area to clear (-1)
INIT30 CLR.L (A0)+ ;Clear data area
DBF D0,INIT30
MOVE.L #SSPDEF,SAVA+28 ;Set default supervisor statck pointer
MOVE.W #SRDEF,SAVSR+2 ;Set default status register
MOVE.L #SIZEDEF,SIZEDIS ;Set default memory display size
BSR TEXT ;Display sign-on message
DC.B CR
ASCII '-- DEBUGGER, V1.0x1 --'
DC.B CR + $80
RTS
;Vector table
VECTBL DC.L SSPDEF ;0 Reset: Initial SSP
DC.L START ;1 Reset: Initial PC
DC.L BE_EXCP ;2 Bus Error
DC.L AE_EXCP ;3 Address Error
DC.L II_EXCP ;4 Illegal Instruction
DC.L ZD_EXCP ;5 Zero Divide
DC.L CI_EXCP ;6 CHK Instruction
DC.L TV_EXCP ;7 TRAPV Instruction
DC.L PV_EXCP ;8 Privilege Violation
DC.L TR_EXCP ;9 Trace
DC.L LA_EXCP ;10 Line 1010 Emulator
DC.L LF_EXCP ;11 Line 1111 Emulator
DC.L SI_EXCP ;12 Spurious Interrupt
DC.L BP_EXCP ;15 Breakpoint Trap
;======================================================================
;DISPLAY COMMANDS
;----------------------------------------------------------------------
;Dispatch to display routine
;
CMD_D_ BSR GETCH ;Get uppercase character into D0
LEA DCMDTBL.L,A0 ;Point to command search table
BRA EXECUTE ;(PBRA) Call routine to handle command
;Display command table:
DCMDTBL DC.W 'M' ;Display memory
DC.W CMD_DM-DCMDTBL
DC.W CR ;Display memory
DC.W CMD_DM-DCMDTBL
DC.W SPACE ;Display memory ???
DC.W CMD_DM-DCMDTBL
DC.W 'R' ;Display all registers
DC.W CMD_DR-DCMDTBL
DC.W 'D' ;Display data registers
DC.W CMD_DD-DCMDTBL
DC.W 'A' ;Display address registers
DC.W CMD_DA-DCMDTBL
DC.W 'P' ;Display program counter
DC.W CMD_DP-DCMDTBL
DC.W 'U' ;Display user stack pointer
DC.W CMD_DU-DCMDTBL
DC.W 'S' ;Display status register
DC.W CMD_DS-DCMDTBL
DC.W 'B' ;Display breakpoints
DC.W CMD_DB-DCMDTBL
DC.W $00 ;Mark end of table
DC.W CMD_BAD-DCMDTBL ;Routine to handle illegal commands
;----------------------------------------------------------------------
;Up arrow command -- back up and display memory
;
CMD_DMU MOVE.L SIZEDIS,D0 ;Back up two frame lengths
ADD.L D0,D0
SUB.L D0,ADDRDIS ;(PFALL) Fall into display memory
;----------------------------------------------------------------------
;DM command -- display memory
; Format:
;00000400: 0000 1111 2222 3333 4444 5555 6666 7777 ........ ......
;
; Destroys registers D0, A0, and A1
;
CMD_DM BSR BACKUP
BSR HEXIN ;Get address
BEQ.S CDM01 ;Branch if no address given
MOVE.L D0,ADDRDIS ;Set newly specified address
CDM01 MOVEA.L ADDRDIS,A0 ;Get address for start of display
CDM00 MOVE.L A0,D0 ;Display the address
BSR HEX8OUT
BSR TEXT ;Follow it with a colon and 2 spaces
ASCII ': '
DC.B SPACE + $80
MOVEA.L A0,A1 ;Get working copy of address into A1
CDM10 MOVE.B (A1)+,D0 ;Display the byte at the address
BSR HEX2OUT
MOVE.W A1,D0 ;Get current address
BTST #0,D0 ;Is it odd or even?
BNE.S CDM10 ;Branch back if it is odd
BSR SPOUT ;Display a space between words
ANDI.B #$07,D0 ;Is current address evenly divisible by
BNE.S CDM10 ; 8? Branch if not
BSR SPOUT ;Display 2 more spaces
BSR SPOUT
MOVE.W A1,D0 ;Get current address
ANDI.B #$0F,D0 ;Is it evenly divisible by 16?
BNE.S CDM10 ;Branch if not
CDM30 MOVE.B (A0)+,D0 ;Display the ASCII values...
ANDI.B #$7F,D0 ;Convert byte to ASCII
CMPI.B #$20,D0 ;Is it a displayable character?
BHS.S CDM40 ;Branch if yes
MOVEQ #'.',D0 ;Else replace it with a dot
CDM40
CMPI.B #$7F,D0 ;Is it a delete character?
BNE.S CDM50 ;Branch if not
MOVEQ #'.',D0 ;Else replace it with a dot
CDM50
BSR CHOUT ;Display ASCII character
MOVE.W A0,D0 ;Put 2 spaces after the 8th byte
ANDI.B #$07,D0
BNE.S CDM30
BSR SPOUT
BSR SPOUT
MOVE.W A0,D0 ;Put a CRLF after the 16th byte
ANDI.B #$0F,D0
BNE.S CDM30
BSR CRLF
MOVEA.L ADDRDIS,A1 ;Is A1 >= Frame length + ADDRDIS?
ADDA.L SIZEDIS,A1
CMPA.L A1,A0
BLO.S CDM00 ;Loop back if not
MOVE.L A0,ADDRDIS ;Else update default address and exit
RTS
;----------------------------------------------------------------------
;DR command -- display all registers
;
CMD_DR BSR.S CMD_DD ;Display data registers
BSR.S CMD_DA ;Display address registers
BSR.S CMD_DP ;Display PC, etc.
BRA.S CMD_DB ;(PBRA) Display breakpoints
;----------------------------------------------------------------------
;DD command -- display data registers
;
CMD_DD LEA SAVD.L,A0 ;Point to data register table
MOVEQ #'D',D0 ;Get register letter
BRA.S CDR_ ;(PBRA) Display registers
;----------------------------------------------------------------------
;DA command -- display address registers
;
CMD_DA LEA SAVA.L,A0 ;Point to address register table
MOVEQ #'A',D0 ;Get register letter
BRA.S CDR_ ;(PBRA) Display registers
;----------------------------------------------------------------------
;DB command -- display breakpoints
;
CMD_DB LEA BRKATBL.L,A0 ;Point to breakpoint addresses
MOVEQ #'B',D0 ;Get register letter
;(PFALL) CDR_ Display registers
;----------------------------------------------------------------------
;Local subroutine to display registers
; Inputs:
; D0 = Contains character describing register type (D, A, or B)
; A0 = Pointer to table of values for each register
; Destroys D0, D1 and A0.
; Format:
; D0: 01234567 01234567 01234567 01234567 01234567 01234567 ...
;
CDR_ BSR CHOUT ;Display D, A, or B
BSR TEXT
ASCII '0: '
DC.B SPACE + $80
MOVEQ #7,D1
CDR10 MOVE.L (A0)+,D0 ;Get the register's value
BSR HEX8OUT ;Display it
BSR SPOUT ;Followed by a space
CMP.B #4,D1 ;Display 2 more spaces before register 4
BNE.S CDR20 ;Branch if not register 4
BSR SPOUT
BSR SPOUT
CDR20 DBF D1,CDR10
BRA CRLF ;(PBRA) Move to next line and return
;----------------------------------------------------------------------
;DPc, DUsp, & DSr commands -- display program counter, user stack
; pointer, and status register.
; Registers D0-D2/A0 are destroyed.
;
CMD_DP
CMD_DU
CMD_DS BSR TEXT ;Display program counter
ASCII 'PC: '
DC.B SPACE + $80
MOVE.L SAVPC,D0
BSR HEX8OUT
BSR TEXT ;Display user stack pointer
ASCII ' USP: '
DC.B SPACE + $80
MOVE.L SAVUSP,D0
BSR HEX8OUT
BSR TEXT ;Display status register
ASCII ' SR: '
DC.B SPACE + $80
MOVE.L SAVSR,D0
BSR HEX4OUT
BSR TEXT ;Show status register bits
ASCII ' '
DC.B '(' + $80
MOVE.W D0,D1
LEA FLAGS.L,A0 ;Point to list of flag names
MOVEQ #15,D2 ;Display T if trace flag is set
BSR.S FLGOUT
MOVEQ #13,D2 ;Display S if supervisor state
BSR.S FLGOUT
MOVE.W D1,D0 ;Display interrupt level (0..7)
LSR.W #8,D0
BSR HEX1OUT
MOVEQ #4,D2 ;Display status flags: XNZVC
CDS20 BSR.S FLGOUT
DBF D2,CDS20
BSR TEXT
DC.B ')', CR + $80
RTS
;----------------------------------------------------------------------
;Local subroutine to display flag bits.
; Inputs:
; D1 = Copy of status register
; D2 = Bit (flag) in status register to display
; A0 = Pointer to string of flag names
; D0 is destroyed.
;
FLGOUT MOVE.B (A0)+,D0 ;Assume flag is set
BTST D2,D1 ;Test bit in copy of status register
BNE.S FLO10 ;Branch if flag is in fact set
MOVEQ #SPACE,D0 ;Else substitute a space character
FLO10 BRA CHOUT ;(PBRA) Output character and return
FLAGS ASCII 'TSXNZVC' ;Status register flag names
;======================================================================
;SET COMMANDS
;----------------------------------------------------------------------
;Dispatch to routine to set memory and registers
CMD_S_ BSR GETCH ;Get uppercase character into D0
LEA SCMDTBL.L,A0 ;Point to command search table
BRA EXECUTE ;(PBRA) Call routine to handle command
;Set command table:
SCMDTBL DC.W 'M' ;Set memory
DC.W CMD_SM-SCMDTBL
DC.W CR ;Set memory
DC.W CMD_SM-SCMDTBL
DC.W SPACE ;Set memory
DC.W CMD_SM-SCMDTBL
DC.W 'R' ;Set all registers
DC.W CMD_SR-SCMDTBL
DC.W 'D' ;Set data registers
DC.W CMD_SD-SCMDTBL
DC.W 'A' ;Set address registers
DC.W CMD_SA-SCMDTBL
DC.W 'P' ;Set program counter
DC.W CMD_SP-SCMDTBL
DC.W 'U' ;Set user stack pointer
DC.W CMD_SU-SCMDTBL
DC.W 'S' ;Set status register
DC.W CMD_SS-SCMDTBL
DC.W 'B' ;Set breakpoints
DC.W CMD_SB-SCMDTBL
DC.W $00 ;Mark end of table
DC.W CMD_BAD-SCMDTBL ;Routine to handle illegal commands
;----------------------------------------------------------------------
;SM command -- set memory
; Destroys registers D0 and A0
;
CMD_SM CMPI.B #CR,D0 ;If last char input was a CR then
BEQ.S CSM10 ; don't try to look for hex (hangs)
BSR HEXIN ;Get address
BEQ.S CSM10 ;Branch if no address given
MOVE.L D0,ADDRSET ;Set newly specified address
CSM10 MOVEA.L ADDRSET,A0 ;Get address for start of display
MOVE.L A0,D0 ;Display the address
BSR HEX8OUT
BSR TEXT ;Follow it with a colon and 2 spaces
ASCII ': '
DC.B SPACE + $80
MOVE.B (A0)+,D0 ;Display the byte at the address
BSR HEX2OUT
MOVE.B (A0)+,D0 ;Display the next byte
BSR HEX2OUT
BSR TEXT ;Follow it with a...
ASCII ' ='
DC.B SPACE + $80
BSR GETCH ;Get uppercase character into D0
LEA XCMDTBL.L,A0 ;Point to command search table
BSR EXECUTE ;Call routine to handle command
BRA.S CSM10 ;Loop until "." (or CTRL-C)
;Set-memory command table:
XCMDTBL DC.W CR ;Move to next location
DC.W CSMDOWN-XCMDTBL
DC.W DOWN
DC.W CSMDOWN-XCMDTBL
DC.W UP
DC.W CSMUP-XCMDTBL
DC.W '.'
DC.W CSMEXIT-XCMDTBL
DC.W $00 ;End marker flag
DC.W CSMASCI-XCMDTBL ;Assume ASCII and change memory contents
;----------------------------------------------------------------------
;Return from CMD_SM (and SETREGS).
;
CSMEXIT ADDQ.L #4,SP ;Discard first return address
RTS
;----------------------------------------------------------------------
;Move ahead (or down) one word in memory.
;
CSMDOWN ADDQ.L #2,ADDRSET
RTS
;----------------------------------------------------------------------
;Move back (or up) one word in memory.
;
CSMUP SUBQ.L #2,ADDRSET
RTS
;----------------------------------------------------------------------
;Get new value to store into current word
;
CSMASCI MOVEM.L D0/A0,-(SP) ;Save registers
BSR BACKUP ;Reread first hex digit
BSR HEXIN
BNE.S CSMA10 ;Branch if no error
BSR TEXT
ASCII 'HEX NUMBER EXPECTED'
DC.B BEL, CR + $80
BSR OPENI ;Flush the line buffer
BRA.S CSMA90 ;Exit
CSMA10
MOVEA.L ADDRSET,A0 ;Get current address
MOVE.W D0,(A0)+ ;Store hex into word
MOVE.L A0,ADDRSET
CSMA90 MOVEM.L (SP)+,D0/A0 ;Restore registers
RTS
;----------------------------------------------------------------------
;SD command -- set data registers
; Destroys registers D0 and D1
;
CMD_SR ;Also, SR command -- set all registers
CMD_SD BSR HEXIN ;Get register number
ANDI.B #$07,D0 ;Force to legal range
BRA.S SETREGS ;Enter set-register code
;----------------------------------------------------------------------
;SA command -- set address registers
;
CMD_SA BSR HEXIN ;Get register number
ANDI.B #$07,D0 ;Force to legal range
ADDQ.L #8,D0 ;Add address register table offset
BRA.S SETREGS ;Enter set-register code
;----------------------------------------------------------------------
;SP command -- set value of program counter
;
CMD_SP MOVEQ #$10,D0 ;Get offset to PC table entry
BRA.S SETREGS ;Enter set-register code
;----------------------------------------------------------------------
;SU command -- set user stack pointer
;
CMD_SU MOVEQ #$11,D0 ;Get offset to US table entry
BRA.S SETREGS ;Enter set-register code
;----------------------------------------------------------------------
;SS command -- set value of status register
;
CMD_SS MOVEQ #$12,D0 ;Get offset to SR table entry
BRA.S SETREGS ;Enter set-register code
;----------------------------------------------------------------------
;SB command -- set breakpoints
;
CMD_SB BSR HEXIN ;Get breakpoint number
ANDI.B #$07,D0 ;Force to legal range
ADDI.B #$18,D0 ;Add breakpoint table offset
;Enter set-register code
;----------------------------------------------------------------------
;Set register values (D0-D7, A0-A7, PC, USP, SR, B0-B7).
; Inputs:
; D0 = Register number (0..$12)
;
; Destroys registers D0, D1, and A1
;
SETREGS BSR OPENI ;Flush line to save confusion
MOVE.L D0,D1 ;Save the register number in D1
SETR00 MOVE.L D1,D0 ;A1 = D1 * 4 + SAVD
ASL.L #2,D0
ADD.L #SAVD,D0
MOVEA.L D0,A1
CMPI.B #$08,D1 ;Is it a data register?
BGE.S SETR10 ;Branch if not
MOVEQ #'D',D0
BRA.S SHOREG
SETR10
CMPI.B #$10,D1
BGE.S SETR20
MOVEQ #'A',D0
BRA.S SHOREG
SETR20
BNE.S SETR23 ;Branch if not PC
BSR TEXT ;Display program counter
ASCII 'PC: '
DC.B SPACE + $80
MOVE.L (A1),D0 ;Display the current value
BSR HEX8OUT
BRA.S SETR30
SETR23
CMPI.B #$11,D1 ;Is it the USP?
BNE.S SETR26 ;Branch if not
BSR TEXT ;Display user stack pointer
ASCII 'USP: '
DC.B SPACE + $80
MOVE.L (A1),D0 ;Display the current value
BSR HEX8OUT
BRA.S SETR30
SETR26
CMPI.B #$12,D1 ;Is it the SR?
BNE.S SETR28 ;Branch if not
BSR TEXT ;Display status register
ASCII 'SR: '
DC.B SPACE + $80
MOVE.L (A1),D0 ;Display the current value
BSR HEX4OUT
BRA.S SETR30
SETR28
MOVEQ #'B',D0 ;It must be a breakpoint
SHOREG BSR CHOUT ;Display register letter
MOVE.L D1,D0 ;Get register index
ANDI.B #$07,D0 ;Mask to 0..7 range
BSR HEX1OUT
BSR TEXT ;Follow it with a colon and 2 spaces
ASCII ': '
DC.B SPACE + $80
MOVE.L (A1),D0 ;Display the current value
BSR HEX8OUT
SETR30
BSR TEXT ;Follow it with a...
ASCII ' ='
DC.B SPACE + $80
BSR GETCH ;Get uppercase character into D0
LEA RCMDTBL.L,A0 ;Point to command search table
BSR EXECUTE ;Call routine to handle command
BRA SETR00 ;Loop until "." (or CTRL-C)
;Set-register command table:
RCMDTBL DC.W '.'
DC.W CSMEXIT-RCMDTBL
DC.W CR ;Move to next location
DC.W CSRDOWN-RCMDTBL
DC.W DOWN
DC.W CSRDOWN-RCMDTBL
DC.W UP
DC.W CSRUP-RCMDTBL
DC.W $00 ;End marker flag
DC.W CSRASCI-RCMDTBL ;Assume ASCII and change memory contents
;----------------------------------------------------------------------
;Move ahead (or down) a register
;
CSRDOWN ADDQ.B #1,D1
CMPI.B #$1F,D1
BLS.S CSRD10
MOVEQ #0,D1
CSRD10 CMPI.B #$13,D1
BNE.S CSRD20
MOVEQ #$18,D1
CSRD20 RTS
;----------------------------------------------------------------------
;Move back (or up) one register
;
CSRUP SUBQ.B #1,D1
BGE.S CSRU10
MOVEQ #$1F,D1
CSRU10 CMPI.B #$17,D1
BNE.S CSRU20
MOVEQ #$12,D1
CSRU20 RTS
;----------------------------------------------------------------------
;Get new value to store into current register
; Inputs A1 = Pointer to the entry in the table for the current register
;
CSRASCI MOVEM.L D0,-(SP) ;Save registers
BSR BACKUP ;Reread first hex digit
BSR HEXIN
BNE.S CSRA10 ;Branch if no error
BSR TEXT
ASCII 'HEX NUMBER EXPECTED'
DC.B BEL, CR + $80
BSR OPENI ;Flush the line buffer
BRA.S CSRA90 ;Exit
CSRA10
MOVE.L D0,(A1) ;Store hex into register save loc
BSR.S CSRDOWN ;Get terminator
CSRA90 MOVEM.L (SP)+,D0 ;Restore registers
RTS
;======================================================================
;F command -- fill memory with pattern
; Three arguments must be given.
; FILL (START, END, PATTERN)
; The pattern argument is tested to determine if it is to be repeated
; every byte, word, or long. Word and long patterns have a couple of
; problems. Some word and long patterns are impossible, for example
; $0034 is interpreted as a byte, not a word. FILL (100, 200, 12345678)
; will fill up through location 203, not 200.
;
; Destroys registers D0, D1, and A0.
;
CMD_F BSR HEXIN ;Get START argument
BEQ CMD_BAD ;(PBRA) Must have 3 hex values
MOVEA.L D0,A0 ;Initialize pointer to START
BSR BACKUP ;Check for CR
BSR HEXIN ;Get END argument
BEQ CMD_BAD ;(PBRA) Check for 3 hex values
MOVE.L D0,D1 ;Save END in D1
CMP.L A0,D1 ;If END < START then error
BLO CMD_BAD ;(PBRA)
BSR BACKUP ;Check for CR
BSR HEXIN ;Get PATTERN argument
BEQ CMD_BAD ;(PBRA) Check for 3 hex values
CMPI.L #$000000FF,D0 ;Is it only one byte?
BHI.S FIL20 ;Branch if not
FIL10 MOVE.B D0,(A0)+ ;Fill START through END with byte
CMPA.L D1,A0 ; PATTERN
BLS.S FIL10
BRA.S FIL90 ;Exit
FIL20
CMPI.L #$0000FFFF,D0 ;Is it one word?
BHI.S FIL40 ;Branch if not -- it's a long
FIL30 MOVE.W D0,(A0)+ ;Fill START through END with word
CMPA.L D1,A0 ; PATTERN
BLS.S FIL30
BRA.S FIL90 ;Exit
FIL40
FIL50 MOVE.L D0,(A0)+ ;Fill START through END with long
CMPA.L D1,A0 ; PATTERN
BLS.S FIL50
FIL90 RTS
;----------------------------------------------------------------------
;M command -- move a block of memory
; The block begins at the first argument, START, and ends at the second
; argument, END. The beginning of the block is moved to the address
; given by the third argument, TO.
; MOVE (START, END, TO)
;
; Destroys registers D0, D1, A0, and A1.
;
CMD_M BSR HEXIN ;Get START argument
BEQ CMD_BAD ;(PBRA) Must have 3 hex values
MOVEA.L D0,A0 ;Point A0 to START
BSR BACKUP ;Check for CR
BSR HEXIN ;Get END argument
BEQ CMD_BAD ;(PBRA) Check for 3 hex values
CMP.L A0,D0 ;If END < START then error
BLO CMD_BAD ;(PBRA)
SUB.L A0,D0 ;LENGTH:= END - START + 1
ADDQ.L #1,D0
MOVE.L D0,D1 ;Save LENGTH in D1
BSR BACKUP ;Check for CR
BSR HEXIN ;Get TO argument
BEQ CMD_BAD ;(PBRA) Check for 3 hex values
MOVEA.L D0,A1
MOVE.W D1,D0 ;Get low 16 bits of LENGTH into D0 and
SWAP D1 ; high 16 bits into D1
CMPA.L A0,A1 ;If TO > START (i.e: moving forward in
BEQ.S MOVE90 ; memory) then don't branch, else
BLO.S MOVE20 ; enter loop checking for LENGTH = 0
; (this is actually unnecessary)
ADDA.L D0,A1 ;Move starting at the end of the block
ADDA.L D0,A0 ;Add LENGTH to TO and START
BRA.S MOVE40 ;Enter loop checking for LENGTH = 0
MOVE10 MOVE.B (A0)+,(A1)+ ;Move block backward, pointers forward
MOVE20 DBF D0,MOVE10 ;Loop unitl D0 = -1
DBF D1,MOVE10 ; and also D1 = -1
BRA.S MOVE90 ;Exit
MOVE30 MOVE.B -(A0),-(A1) ;Move block forward, pointers backward
MOVE40 DBF D0,MOVE30 ;Loop unitl D0 = -1
DBF D1,MOVE30 ; and also D1 = -1
MOVE90 RTS
;----------------------------------------------------------------------
;Z command -- set memory display frame size.
;
CMD_Z BSR HEXIN ;Get size argument
BEQ CMD_BAD ;(PBRA) We must have it, else error
MOVE.L D0,SIZEDIS ;Set new memory display size
RTS
;======================================================================
;EXECUTE COMMANDS
;----------------------------------------------------------------------
;T command -- trace program
;
CMD_T BSET #7,SAVSR+2 ;Set trace bit in status register
BSR HEXIN ;Read entry point
BEQ.S TR10
MOVE.L D0,SAVPC ;Update in save PC
TR10
CLR.B BPFLAG ;Clear execute thru breakpoint flag
BRA GO50 ;Enter common code
;----------------------------------------------------------------------
;G command -- start or continue program
;
CMD_G BSR HEXIN ;Read entry point
BEQ.S GO10
MOVE.L D0,SAVPC ;Update in save PC
GO10
CLR.B BPFLAG ;Clear execute thru breakpoint flag
BCLR #7,SAVSR+2 ;Clear trace mode
;Handle breakpoints. This inserts the breakpoint TRAP #$F instructions.
; If we are about to execute a breakpoint, the TRAP is not inserted.
; Instead, the trace flag is set along with the BPFLAG which allows the
; instruction at the breakpoint to be executed. The trace flag causes
; control to be returned to the debugger which clears the trace flag
; and resumes execution of the user's program. The BPFLAG is used to
; distinguish this one-instruction trace from trace mode.
LEA BRKATBL.L,A1 ;Point to breakpoint table
LEA BRKITBL.L,A2
MOVEQ #7,D0 ;Set loop counter (7..0)
GO20 MOVEA.L (A1)+,A0 ;Get breakpoint address
MOVE.W (A0),(A2)+ ;Save instruction in table
CMPA.L SAVPC,A0 ;Are we about to execute a breakpoint?
BNE.S GO30 ;Branch if not
BSET #7,SAVSR+2 ;Set trace bit
ST BPFLAG ;Set flag to continue thru breakpoint
BRA.S GO40
GO30 MOVE.W #$4E4F,(A0) ;Replace instruction with TRAP #15
GO40 DBF D0,GO20 ;Loop for all breakpoints
;Enter from "continue past breakpoint" code
GO50 MOVEA.L SAVUSP,A0 ;Restore user stack pointer
MOVE A0,USP
MOVEA.L SAVA+28,SP ;Restore supervisor stack pointer
MOVE.L SAVPC,-(SP) ;Stack saved PC
MOVE.W SAVSR+2,-(SP) ;Stack saved SR
MOVEM.L SAVD,D0-D7/A0-A6 ;Restore user's registers
ST GOFLAG ;Indicate that the user's prog is going
RTE ;Restore PC & SR and resume execution
;======================================================================
;EXCEPTION HANDLERS
;----------------------------------------------------------------------
;Jump table for exception handlers.
; The exception vectors point to the various entries in this table.
; There is an entry for each type of exception. BSR.S pushes a return
; address which is used to determine which type of exception occurred.
;
BE_EXCP BSR.S EXCP10 ;2 Bus Error
AE_EXCP BSR.S EXCP10 ;3 Address Error
II_EXCP BSR.S EXCP20 ;4 Illegal Instruction
ZD_EXCP BSR.S EXCP20 ;5 Zero Divide
CI_EXCP BSR.S EXCP20 ;6 CHK Instruction
TV_EXCP BSR.S EXCP20 ;7 TRAPV Instruction
PV_EXCP BSR.S EXCP20 ;8 Privilege Violation
TR_EXCP BSR.S EXCP20 ;9 Trace
LA_EXCP BSR.S EXCP20 ;10 Line 1010 Emulator
LF_EXCP BSR.S EXCP20 ;11 Line 1111 Emulator
SI_EXCP BSR.S EXCP20 ;12 Spurious Interrupt
IN_EXCP BSR.S EXCP20 ;13 Unassigned Interrupt
TI_EXCP BSR.S EXCP20 ;14 Unassigned TRAP Instruction
BP_EXCP BSR.S EXCP20 ;15 TRAP #$F (Breakpoint)
UA_EXCP BSR.S EXCP20 ;16 Unassigned exception
;----------------------------------------------------------------------
;Exception handler for bus errors and address errors (group 0).
; After D0 and A0 are pushed, the supervisor stack looks like this:
;
; SSP --> 0 D0 Hi
; 2 D0 Lo
; 4 A0 Hi
; 6 A0 Lo
; 8 Return Address Hi
; 10 Return Address Lo
; 12 Function Codes, etc.
; 14 Access Address Hi
; 16 Access Address Lo
; 18 Instruction Register
; 20 Status Register
; 22 PC Hi
; 24 PC Lo
;
;
EXCP10 MOVEM.L D0/A0,-(SP) ;Save registers
MOVE.L 14(SP),ACCESS ;Save access address and function
MOVE.W 12(SP),FUNCODE ; codes to be displayed later
MOVEA.L 22(SP),A0 ;Get PC
MOVE.W 18(SP),D0 ;Get instruction register
CMP.W -(A0),D0 ;Since the PC value varies a few words,
BEQ.S EXCP12 ; look for the instruction in the code
CMP.W -(A0),D0 ; that matches the instruction register
BEQ.S EXCP12 ; and set PC to point to it.
CMP.W -(A0),D0
BEQ.S EXCP12
CMP.W -(A0),D0
BEQ.S EXCP12
SUBQ #2,A0
EXCP12
MOVE.L A0,22(SP) ;Restore corrected PC
MOVEM.L (SP)+,D0/A0 ;Restore registers
MOVE.L (SP),8(SP) ;Move return address ahead and adjust
ADDQ #8,SP ; stack to look like a group 1 or 2
; execption, and fall into EXCP20
;----------------------------------------------------------------------
;Exception handler for group 1 and 2 exceptions.
; Upon entering, the supervisor stack looks like this:
;
; SSP --> 0 Return Address Hi (exception type)
; 2 Return Address Lo (exception type)
; 4 Status Register
; 6 PC Hi
; 8 PC Lo
;
;
EXCP20 TST.B GOFLAG ;Don't save registers unless we were
BEQ.S EXCP25 ; running the user's program
MOVEM.L D0-D7/A0-A7,SAVD ;Save all user registers
EXCP25
MOVEA.L (SP)+,A1 ;Get address of routine which called
SUBQ.L #2,A1 ; this exception handler and save in A1
MOVE.W (SP)+,D0 ;Get SR and PC from the stack
MOVEA.L (SP)+,A0
TST.B GOFLAG ;Don't save registers unless we were
BEQ.S EXCP28 ; running the user's program
MOVE.W D0,SAVSR+2 ;Save SR
MOVE.L A0,SAVPC ;Save PC
MOVE USP,A0 ;Get user stack pointer
MOVE.L A0,SAVUSP ;Save USP
MOVE.L SP,SAVA+28 ;Save SP
CLR.B GOFLAG ;We're no longer running the user prog
BRA.S EXCP29
EXCP28 BSR CRLF ;New line if internal exception
EXCP29
;Restore all breakpoints with their original instructions
LEA BRKATBL.L,A0 ;Point A0 to breakpoint table
LEA BRKITBL.L,A2
MOVEQ #7,D0 ;Loop for 8 breakpoints (0..7)
EXCP30 MOVEA.L (A0)+,A3 ;Get the address of the breakpoint
MOVE.W (A2)+,(A3) ;Restore the original instruction
DBF D0,EXCP30 ;Loop for all breakpoints
LEA TR_EXCP.L,A0 ;Is this a trace exception?
CMPA.L A0,A1
BNE.S EXCP50 ;Branch if not
;Check for continue through breakpoint (i.e. a one-instruction trace)?
TST.B BPFLAG ;Is this a continue through breakpoint?
BEQ.S EXCP40 ;Branch if not
CLR.B BPFLAG
BCLR #7,SAVSR+2 ;Turn trace bit off
;Insert the missing breakpoint. (We must insert them all, because we
; don't know how many words were in the last instruction.)
LEA BRKATBL.L,A1 ;Point to breakpoint table
LEA BRKITBL.L,A2
MOVEQ #7,D0 ;Set loop counter (7..0)
EXCP35 MOVEA.L (A1)+,A0 ;Get breakpoint address
MOVE.W (A0),(A2)+ ;Save instruction in table
MOVE.W #$4E4F,(A0) ;Replace instruction with TRAP #15
DBF D0,EXCP35 ;Loop for all breakpoints
BRA GO50 ;Resume execution of user's program
;Handle normal trace exception
EXCP40 BSR TEXTABO ;Display trace message
BSR CMD_DR ;Display registers
LEA CMDTBL.L,A0 ;Point to command table
PEA GETCMD.L ;Push ret adr of com loop
BSR TEXT ;Display prompt for special trace mode
DC.B 'T', '>' + $80
BSR GETCH ;Get next chr
CMP.B #CR,D0 ;Carriage return?
BNE EXECUTE ;(PBNE) No, search for command
BSET #7,SAVSR+2 ;Set trace bit in status register
BRA TR10
;Check if this is a breakpoint
EXCP50 LEA BP_EXCP.L,A0 ;Is it a TRAP #$F?
CMPA.L A0,A1
BNE.S EXCP60 ;Branch if not
;Is the TRAP #$F actually one of our breakpoints?
;If an entry in BRKATBL = SAVPC -2 then it is.
MOVEA.L SAVPC,A0 ;Get PC and adjust it to point to the
SUBQ.L #2,A0 ; TRAP #$F instruction
LEA BRKATBL.L,A2 ;Point to breakpoint address table
MOVEQ #7,D1 ;Loop for 8 breakpoints
EXCP53 CMPA.L (A2)+,A0 ;Does this entry match the address?
DBEQ D1,EXCP53 ;Decrement and branch if not
BNE.S EXCP59 ;Branch if not
MOVE.L A0,SAVPC ;Fix PC to point to address of TRAP
BSR TEXTABO ;Display breakpoint message
BSR CMD_DR ;Display registers
BRA GETCMD ;Enter main loop of debugger
EXCP59 LEA TI_EXCP.L,A1 ;Change "BREAKPOINT" to "TRAP"
;Check for interrupt exception
EXCP60 LEA IN_EXCP.L,A0 ;Interrupt exception?
CMPA.L A0,A1
BNE.S EXCP70 ;Branch if not
BSR TEXT
ASCII 'INTERRUPT AT LEVEL'
DC.B BEL, SPACE + $80
MOVE SR,D0 ;Get interrupt level from SR
LSR.W #8,D0
BSR HEX1OUT
BSR TEXTABO ;Display message
BRA GETCMD ;Enter main loop of debugger
;Check for TRAP instructions
EXCP70 LEA TI_EXCP.L,A0 ;Trap instruction?
CMPA.L A0,A1
BNE.S EXCP80 ;Branch if not
BSR TEXT
ASCII 'TRAP #'
DC.B BEL, '$' + $80
MOVEA.L SAVPC,A0 ;Get trap level from instruction
MOVE.W -(A0),D0
BSR HEX1OUT
BSR TEXT
ASCII ' INSTRUCTIO'
DC.B 'N' + $80
BSR TEXTABO ;Display message
BRA GETCMD ;Enter main loop of debugger
;Check for bus and address error exceptions
EXCP80 LEA BE_EXCP.L,A0 ;Bus error?
CMPA.L A0,A1
BEQ.S EXCP85 ;Branch if it is
LEA AE_EXCP.L,A0 ;Address error?
CMPA.L A0,A1
BNE.S EXCP90 ;Branch if not
EXCP85
BSR.S BEEP
BSR.S TEXTABO
BSR TEXT
ASCII 'ACCESS ADDRESS:'
DC.B SPACE + $80
MOVE.L ACCESS,D0
BSR HEX8OUT
BSR TEXT
DC.B CR
ASCII 'FUNCTION CODE:'
DC.B SPACE + $80
MOVE.W FUNCODE,D0
BSR HEX2OUT
BSR CRLF
BRA GETCMD ;Enter main loop of debugger
;Display message for remaining exceptions
EXCP90 BSR.S BEEP
BSR TEXTABO ;Display exception error message
BRA GETCMD ;Enter main loop of debugger
;----------------------------------------------------------------------
;Make beep noise
;
BEEP MOVEQ #BEL,D0 ;Beep
BRA CHOUT ;(PBRA)
;----------------------------------------------------------------------
;Display an exception message.
; Inputs:
; A1 = Address of exception handler
; Destroys D0, A0, A1, and A2
;
TEXTABO LEA BE_EXCP.L,A0 ;Get base address of jump table
SUBA.L A0,A1 ;Get word offset for current exception
MOVE.L A1,D0
LEA ABOTBL.L,A2 ;Get pointer to abort table base
MOVEA.W 0(A2,D0.L),A0 ;Get offset to base of message
ADDA.L A2,A0 ;Add base to point to string
BSR TEXTA0 ;(PBRA) Display message and return
BSR TEXT
ASCII ' PC: '
DC.B SPACE + $80
MOVEA.L SAVPC,A0 ;Get current PC
MOVE.L A0,D0 ;Display it
BSR HEX8OUT
BSR TEXT
ASCII ': '
DC.B SPACE + $80
MOVE.W (A0),D0 ;Display instruction at PC
BSR HEX4OUT ; (this is the next instruction to be
BSR CRLF ; executed)
RTS
;Table of pointers to exception messages.
ABOTBL DC.W AB2-ABOTBL
DC.W AB3-ABOTBL
DC.W AB4-ABOTBL
DC.W AB5-ABOTBL
DC.W AB6-ABOTBL
DC.W AB7-ABOTBL
DC.W AB8-ABOTBL
DC.W AB9-ABOTBL
DC.W AB10-ABOTBL
DC.W AB11-ABOTBL
DC.W AB12-ABOTBL
DC.W AB13-ABOTBL
DC.W AB14-ABOTBL
DC.W AB15-ABOTBL
DC.W AB16-ABOTBL
AB2 ASCII 'BUS ERROR'
DC.B SPACE + $80
AB3 ASCII 'ADDRESS ERROR'
DC.B SPACE + $80
AB4 ASCII 'ILLEGAL INSTRUCTION'
DC.B SPACE + $80
AB5 ASCII 'ZERO DIVIDE'
DC.B SPACE + $80
AB6 ASCII 'CHK INSTRUCTION'
DC.B SPACE + $80
AB7 ASCII 'TRAPV INSTRUCTION'
DC.B SPACE + $80
AB8 ASCII 'PRIVILEGE VIOLATION'
DC.B SPACE + $80
AB9 ASCII 'TRACE'
DC.B SPACE + $80
AB10 ASCII 'LINE 1010 EMULATOR'
DC.B SPACE + $80
AB11 ASCII 'LINE 1111 EMULATOR'
DC.B SPACE + $80
AB12 ASCII 'SPURIOUS INTERRUPT'
DC.B SPACE + $80
AB13 DC.B SPACE + $80
AB14 DC.B SPACE + $80
AB15 ASCII 'BREAKPOINT'
DC.B SPACE + $80
AB16 ASCII 'UNASSIGNED EXCEPTION'
DC.B SPACE + $80
;======================================================================
;SUBROUTINES
;----------------------------------------------------------------------
;Search the command table pointed to by A0 for the character in D0.
; This calls the routine which corresponds to the character in D0.
; The calling technique is a bit tricky. When the called command routine
; returns, it returns to the location where this search routine was
; called.
;
EXECUTE MOVE.L D1,-(SP) ;Save D1 (MOVEM won't work here)
MOVE.L A0,-(SP) ; and A0
BRA.S SRCH20 ;Enter search loop
SRCH10 CMP.B D1,D0 ;Does entry match character in D0?
BEQ.S SRCH30 ;Branch if it does -- found
ADDQ.W #2,A0 ;Skip rest of the entry
SRCH20 MOVE.W (A0)+,D1 ;Get character from table
BNE.S SRCH10 ;Loop if not end of table
SRCH30 MOVEA.W (A0)+,A0
ADDA.L (SP),A0 ;Add table base addr, the original A0
MOVE.L 4(SP),D1 ;Restore D1
MOVE.L A0,4(SP) ;Put routine address on stack
MOVEA.L (SP)+,A0 ;Restore A0
RTS ;Call routine
;======================================================================
;INPUT ROUTINES
;----------------------------------------------------------------------
;Get character from keyboard buffer, convert it to upper case, and
; return it in D0.
;
GETCH BSR CHIN
CMPI.B #'a',D0 ;Shift character in D0 to uppercase
BLO.S UPC90
CMPI.B #'z',D0
BHI.S UPC90
ANDI.B #$DF,D0 ;Convert to uppercase
UPC90 RTS
;-----------------------------------------------------------------------
;This routine inputs hex ASCII digits from the terminal and converts
; them to a 32-bit binary value which is returned in D0.
;
; If a hex value is successfully read, the Z flag is returned cleared
; (NE status). This routine skips any initial non-hex characters, but
; always returns when it finds a carriage return (CR). If a CR is read
; before finding any hex digit, this returns with the Z flag set (EQ
; status) and D0 = 0. A Hex value is normally terminated by a non-hex
; character, such as a space or CR.
;
; If the hex value is more than 8 digits long, only the first 8 digits
; will be read in, thus allowing additional calls to handle all of the
; digits.
;
; The hex characters A - F may be lowercase (a - f).
;
; Register Usage:
; D0 = Digit
; D1 = Accumulated value
; D2 = Digit counter
;
;
HEXIN MOVEM.L D1-D2,-(SP) ;Save registers
MOVEQ #0,D1 ;Clear result register
MOVEQ #7,D2 ;Init digit counter (7 down through 0)
HEXI00 BSR CHIN ;Get character
CMPI.B #CR,D0 ;Is it a carriage return?
BEQ.S HEXI90 ;Branch if yes -- exit
CMPI.B #UP,D0 ;Is it an up arrow?
BEQ.S HEXI90 ;Branch if yes -- exit
CMPI.B #DOWN,D0 ;Is it a down arrow?
BEQ.S HEXI90 ;Branch if yes -- exit
CMPI.B #'0',D0 ;Is character in range 0 thru 9?
BLO.S HEXI40 ;Branch if not
CMPI.B #'9',D0
BHI.S HEXI20 ;(May be A-F)
SUBI.B #'0',D0 ;Convert ASCII to binary value
BRA.S HEXI30 ;Go combine with other digits
HEXI20 ANDI.B #$DF,D0 ;Force to uppercase
CMPI.B #'A',D0 ;Is character in range A through F?
BLO.S HEXI40 ;Branch if not -- it's not hex
CMPI.B #'F',D0
BHI.S HEXI40
SUBI.B #'A'-10,D0 ;Convert ASCII to binary value
HEXI30 ASL.L #4,D1 ;Multiply current value by 16
ADD.B D0,D1 ;Add new digit
DBF D2,HEXI00 ;Exit if we have 8 digits
HEXI40 CMPI.B #7,D2 ;Did we find a hex digit?
BEQ.S HEXI00 ;Branch if not -- keep trying
HEXI90 MOVE.L D1,D0 ;Return the hex value in D0
CMPI.B #7,D2 ;Set Z flag if no digits were read
MOVEM.L (SP)+,D1-D2 ;Restore registers
RTS
;======================================================================
;OUTPUT ROUTINES
;----------------------------------------------------------------------
;Output a space character.
;
SPOUT MOVE.L D0,-(SP) ;Save D0
MOVEQ #SPACE,D0 ;Load a space character
BSR CHOUT ;Output it
MOVE.L (SP)+,D0 ;Restore D0
RTS
;----------------------------------------------------------------------
;Output a text string. The string immediately follows the call to this
; routine. I.e:
; BSR TEXT ;Call to this subroutine
; ASCII 'STRIN' ;String to output
; DC.B 'G' + $80 ;Last character must have MSB set
;
TEXT MOVEM.L A0/A1,-(SP) ;Save registers
MOVEA.L 8(SP),A0 ;Get the "return address" which points
MOVEA.L A0,A1 ; to the text string, and get a copy
TXT10 TST.B (A1)+ ;Scan for the end-of-string (MSB set)
BPL.S TXT10 ;Loop unitl the last character is found
ADDQ.L #1,A1 ;Set up the real return address
MOVE.L A1,8(SP) ;Make sure it is on the word boundary
ANDI.B #$FE,11(SP) ; following the string
BSR.S TEXTA0 ;Output the string pointed to by A0
MOVEM.L (SP)+,A0/A1 ;Restore registers
RTS
;----------------------------------------------------------------------
;Output a text string pointed to by A0.
; The string is terminated with a character having its MSB set.
;
TEXTA0 MOVEM.L D0/A0,-(SP) ;Save registers
BRA.S TXTA20 ;Enter loop
TXTA10 BSR CHOUT ;Output D0
TXTA20 MOVE.B (A0)+,D0 ;Get char from string
BPL.S TXTA10 ;Loop unitl the last character
ANDI.B #$7F,D0 ;Clear MSB
BSR CHOUT ;Output D0
MOVEM.L (SP)+,D0/A0 ;Restore registers
RTS
;----------------------------------------------------------------------
;Output D0 in ASCII hex (8 digits).
;
HEX8OUT SWAP D0 ;Get high word
BSR.S HEX4OUT ;Output it
SWAP D0 ;(PFALL) get low word back
;----------------------------------------------------------------------
;Output D0 in ASCII hex (4 digits)
;
HEX4OUT ROR.W #8,D0 ;Move high byte down (and save low byte)
BSR.S HEX2OUT ;Output it
ROR.W #8,D0 ;(PFALL) get low byte
;----------------------------------------------------------------------
;Output D0 in ASCII hex (2 digits)
;
HEX2OUT ROR.B #4,D0 ;Move high nybble down (save low nybble)
BSR.S HEX1OUT ;Output it
ROR.B #4,D0 ;(PFALL) get low nybble
;----------------------------------------------------------------------
;Output D0 in ASCII hex (1 digit)
;
HEX1OUT MOVE.B D0,-(SP) ;Save D0
ANDI.B #$0F,D0 ;Work with low nybble only
CMPI.B #10,D0
BLO.S H1O10
ADDQ.B #7,D0
H1O10 ADDI.B #'0',D0 ;Convert to ASCII
BSR CHOUT ;Output digit
MOVE.B (SP)+,D0 ;Restore D0
RTS
;======================================================================
;CONSOLE HANDLER ROUTINES
;
OPEN BSR.S OPENI
BRA.S OPENO
;
CRLF MOVE.L D0,-(SP)
MOVEQ #CR,D0
BSR.S CHOUT
MOVE.L (SP)+,D0
RTS
;
BACKUP ST BKFLAG
RTS
;
OPENI CLR.B BKFLAG
MOVEM.L A6,-(SP)
CLR.B DEVICE
MOVEA.W #0,A6
JSR VDEVHAN
MOVEA.L (SP)+,A6
RTS
;
OPENO MOVEM.L A6,-(SP)
CLR.B DEVICE
MOVEA.W #4,A6
JSR VDEVHAN
MOVEA.L (SP)+,A6
RTS
;
CHIN TST.B BKFLAG
BEQ.S CHIN20
CLR.B BKFLAG
MOVEQ #0,D0
MOVE.B BKCHAR,D0
BRA.S CHIN90
CHIN20
MOVEM.L A6,-(SP)
CLR.B DEVICE
MOVEA.W #8,A6
JSR VDEVHAN
MOVE.B D0,BKCHAR
MOVEA.L (SP)+,A6
CHIN90 RTS
;
CHOUT MOVE.L A6,-(SP)
CLR.B DEVICE
MOVEA.W #12,A6
JSR VDEVHAN
MOVEA.L (SP)+,A6
RTS
;----------------------------------------------------------------------
;APEX SYSPAG PARAMETERS
END EQU @
ORG USRMEM
DC.L BASE
ORG PROSIZ
DC.L [END-BASE+255]/$100
END
----------
;APEX SYSPAG PARAMETERS
END EQU @
ORG USRMEM
DC.L BA